package outbound_task

import (
	"context"
	"fmt"
	"git.mycaigou.com/gfyx/common/tenant_db"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/common/constants"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/common/utils"
	"git.mycaigou.com/gfyx/micro-gfyx-oppty-service/infrastructure/repository/base/user"
	"git.myscrm.cn/golang/stark/v4"
	"gorm.io/gorm"
)

type outBoundRepository struct {
	tenant_db.TenantDB
}

func NewOutBoundRepository() OutBoundTaskRepositoryIface {
	return &outBoundRepository{}
}

// SaveTask 保存任务表数据
func (r *outBoundRepository) SaveTask(ctx context.Context, po *GfyxOutboundTaskPo) (*GfyxOutboundTaskPo, error) {
	result := r.GetTenantDB(ctx).Table(po.TableName()).Save(po)
	if result.Error != nil {
		stark.Logger.Errorf(ctx, "SaveTask save data : %+v, error: %+v", po, result.Error)
		return nil, result.Error
	}

	return po, nil
}

// UpdateTask 更新任务
func (r *outBoundRepository) UpdateTask(ctx context.Context, conditions map[string]interface{}, columns map[string]interface{}) (bool, error) {
	err := r.GetTenantDB(ctx).Table(GfyxOutboundTaskPo{}.TableName()).
		Where(conditions).
		Updates(columns).
		Error
	if err != nil {
		stark.Logger.Errorf(ctx, "repository-method:UpdateTask, err:%v", err)
		return false, err
	}
	return true, nil
}

// UpdateTaskLog 更新任务记录
func (r *outBoundRepository) UpdateTaskLog(ctx context.Context, db *gorm.DB, conditions map[string]interface{}, columns map[string]interface{}) (bool, error) {
	err := db.Table(GfyxOutboundTaskLogPo{}.TableName()).
		Where(conditions).
		Updates(columns).
		Error
	if err != nil {
		stark.Logger.Errorf(ctx, "repository-method:UpdateTaskLog, err:%v", err)
		return false, err
	}
	return true, nil
}

// InsertTaskLogChangeRecord 写入外呼回调日志表变更记录表,如客户意向的调整
func (r *outBoundRepository) InsertTaskLogChangeRecord(ctx context.Context, db *gorm.DB, record *GfyxOutboundTaskLogChangeRecordPo) error {
	err := r.GetTenantDB(ctx).Create(record).Error
	if err != nil {
		stark.Logger.Errorf(ctx, "repository-method:InsertTaskLogChangeRecord, err:%v", err)
	}
	return err
}

// GetTaskByTaskIds 通过任务ID获取任务表数据
func (r *outBoundRepository) GetTaskByTaskIds(ctx context.Context, taskIds []int64) ([]*GfyxOutboundTaskPo, error) {
	var list []*GfyxOutboundTaskPo
	err := r.GetTenantDB(ctx).Table(GfyxOutboundTaskPo{}.TableName()).
		Where("real_task_id in (?)", taskIds).
		Where("is_deleted = ?", constants.IsDeletedFalse).
		Find(&list).
		Error

	if err != nil && err != gorm.ErrRecordNotFound {
		return nil, err
	}

	return list, nil
}

// GetTaskByRealTaskId 通过百应任务id获取任务表数据
func (r *outBoundRepository) GetTaskByRealTaskId(ctx context.Context, realTaskId int64) (*GfyxOutboundTaskPo, error) {
	var po GfyxOutboundTaskPo
	err := r.GetTenantDB(ctx).Table(GfyxOutboundTaskPo{}.TableName()).
		Where("real_task_id = ?", realTaskId).
		Where("is_deleted = ?", constants.IsDeletedFalse).
		Find(&po).
		Error

	if err != nil && err != gorm.ErrRecordNotFound {
		stark.Logger.Errorf(ctx, "repository-method:GetTaskByRealTaskId, err:%v", err)
		return nil, err
	}

	return &po, nil
}

// SaveTaskPushUser 保存用户推送表记录
// 任务表与用户推送表的配置 1对多的关系，故每次操作时需要对原先的数据进行删除后再插入
func (r *outBoundRepository) SaveTaskPushUser(ctx context.Context, taskId int64, pushUser []*GfyxOutboundTaskPushUserPo) (bool, error) {
	// 删除原先的数据
	db := r.GetTenantDB(ctx).Table(GfyxOutboundTaskPushUserPo{}.TableName())
	if err := db.Where("task_id = ?", taskId).Updates(map[string]interface{}{"is_deleted": 1, "modified_by": "update-del"}).Error; err != nil {
		stark.Logger.Errorf(ctx, "Delete task push user error, error: %+v", err)
		return false, err
	}
	// 再插入新的数据
	if err := r.GetTenantDB(ctx).Table(GfyxOutboundTaskPushUserPo{}.TableName()).Create(&pushUser).Error; err != nil {
		stark.Logger.Errorf(ctx, "insert task push user error, error: %+v", err)
		return false, err
	}
	return true, nil
}

func (r *outBoundRepository) GetTaskPushUserByRealTaskId(ctx context.Context, realTaskId int64) ([]*GfyxOutboundTaskPushUserPo, error) {
	db := r.GetTenantDB(ctx).Table(GfyxOutboundTaskPushUserPo{}.TableName())
	var result []*GfyxOutboundTaskPushUserPo
	err := db.Where("real_task_id = ? and is_deleted = ?", realTaskId, constants.IsDeletedFalse).Find(&result).Error
	if err != nil && err != gorm.ErrRecordNotFound {
		return result, err
	}
	return result, nil
}

func (r *outBoundRepository) SaveTaskLog(ctx context.Context, po *GfyxOutboundTaskLogPo) (*GfyxOutboundTaskLogPo, error) {
	var count int64
	err := r.GetTenantDB(ctx).Table(po.TableName()).Where("task_id = ? and call_instance_id = ? and is_deleted = 0", po.TaskId, po.CallInstanceId).Count(&count).Error
	if err != nil {
		return nil, err
	}

	// 避免回调重试导致的记录写多了
	if count == 0 {
		err = r.GetTenantDB(ctx).Table(po.TableName()).Create(po).Error
		if err != nil {
			return nil, err
		}
	}
	return po, nil
}

func (r *outBoundRepository) QueryTaskLogList(ctx context.Context, condition map[string]interface{}, pageInfo *utils.PageInfo) (int64, []*GfyxOutboundTaskLogPo, error) {
	var result []*GfyxOutboundTaskLogPo
	var count int64
	db := r.GetTenantDB(ctx).Table(GfyxOutboundTaskLogPo{}.TableName()) //.Where(condition)

	if condition != nil {
		if keyword, ok := condition["keyword"]; ok {
			db = db.Where(fmt.Sprintf("mobile like '%%%s%%' or company_name like '%%%s%%'", keyword, keyword))
			delete(condition, "keyword")
		}
		if startDate, ok := condition["start_date"]; ok {
			db = db.Where("start_time >= ?", startDate)
			delete(condition, "start_date")
		}
		if endDate, ok := condition["end_date"]; ok {
			db = db.Where("end_time <= ?", endDate)
			delete(condition, "end_date")
		}
		if durationMin, ok := condition["duration_min"]; ok {
			db = db.Where("duration >= ?", durationMin)
			delete(condition, "duration_min")
		}
		if durationMax, ok := condition["duration_max"]; ok {
			db = db.Where("duration <= ?", durationMax)
			delete(condition, "duration_max")
		}
		if chatRoundMin, ok := condition["chat_round_min"]; ok {
			db = db.Where("chat_round >= ?", chatRoundMin)
			delete(condition, "chat_round_min")
		}
		if chatRoundMax, ok := condition["chat_round_max"]; ok {
			db = db.Where("chat_round <=?", chatRoundMax)
			delete(condition, "chat_round_max")
		}
		if finishStatus, ok := condition["finish_status"]; ok {
			db = db.Where("finish_status in (?)", finishStatus)
			delete(condition, "finish_status")
		}
		if intention, ok := condition["intention"]; ok {
			db = db.Where("intention in (?)", intention)
			delete(condition, "intention")
		}
		if ids, ok := condition["ids"]; ok {
			db = db.Where("id in (?)", ids)
			delete(condition, "ids")
		}
		if len(condition) > 0 {
			db = db.Where(condition)
		}
	}

	err := db.Count(&count).Error
	if err != nil {
		return 0, nil, err
	}

	if pageInfo != nil && pageInfo.PageSize > 0 && pageInfo.Page > 0 {
		db = db.Offset((pageInfo.Page - 1) * pageInfo.PageSize).Limit(pageInfo.PageSize)
	}

	err = db.Order("id desc").Find(&result).Error
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			return 0, result, nil
		}
		return 0, nil, err
	}
	return count, result, nil
}

func (r *outBoundRepository) GetTaskLogByCallInstanceId(ctx context.Context, callInstanceId int64) (*GfyxOutboundTaskLogPo, error) {
	result := &GfyxOutboundTaskLogPo{}
	db := r.GetTenantDB(ctx).Table(GfyxOutboundTaskLogPo{}.TableName())
	err := db.Where("call_instance_id = ? and is_deleted = 0", callInstanceId).First(&result).Error
	if err != nil && err != gorm.ErrRecordNotFound {
		return result, err
	}
	return result, nil
}

func (r *outBoundRepository) GetTaskList(ctx context.Context, condition map[string]interface{}, pageInfo *utils.PageInfo) (int64, []*GfyxOutboundTaskPo, error) {
	list := make([]*GfyxOutboundTaskPo, 0)
	tableName := GfyxOutboundTaskPo{}.TableName() + " t"
	userTableName := user.GfyxUserPo{}.TableName() + " u"
	fields := "t.id,t.task_name,t.user_id,t.real_task_id,t.seat_quota,t.status,u.name as created_by,t.created_on"
	db := r.GetTenantDB(ctx).Table(tableName).Select(fields).
		Joins("left join "+userTableName+" on t.user_id = u.id").
		Where("t.is_deleted = ?", constants.IsDeletedFalse)
	if _, ok := condition["t.real_task_ids"]; ok {
		db = db.Where("t.real_task_id in (?)", condition["t.real_task_ids"])
		delete(condition, "t.real_task_ids")
	}
	db = db.Where(condition)
	var total int64
	err := db.Count(&total).Error
	if err != nil {
		return 0, nil, err
	}

	if pageInfo != nil && pageInfo.Page > 0 && pageInfo.PageSize > 0 {
		pageInfo.Total = total
		db = db.Offset((pageInfo.Page - 1) * pageInfo.PageSize).Limit(pageInfo.PageSize)
	}
	err = db.Find(&list).Error
	return total, list, err
}
